//The MIT License
//
//Copyright (c) 2009 nodchip
//
//Permission is hereby granted, free of charge, to any person obtaining a copy
//of this software and associated documentation files (the "Software"), to deal
//in the Software without restriction, including without limitation the rights
//to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
//copies of the Software, and to permit persons to whom the Software is
//furnished to do so, subject to the following conditions:
//
//The above copyright notice and this permission notice shall be included in
//all copies or substantial portions of the Software.
//
//THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
//IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
//FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
//AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
//LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
//OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
//THE SOFTWARE.
package tv.dyndns.kishibe.client.packet;

import java.util.HashMap;
import java.util.Map;

import tv.dyndns.kishibe.client.Constant;
import tv.dyndns.kishibe.client.geom.Point;
import tv.dyndns.kishibe.client.geom.Polygon;

public class PacketProblemData extends PacketProblemDataMinimum {
	// 改行・HTMLにヤバイ記号・SQLインジェクション関連は%～に置き換えられて保存される
	public String sentence; // 問題文
	public String answer[];// 解答
	public String choice[];// 選択肢
	public String creator;// 作成者
	public String note;// ノート
	public String[] randomizedAnswer;// ランダマイズ順列
	public String[] randomizedChoice;// ランダマイズ順列
	public boolean imageAnswer;// 画像解答
	public boolean imageChoice;// 画像選択肢
	public int voteGood;// 投票(良)
	public int voteBad;// 投票(悪)

	public void setSentence(String s) {
		// 保存用の記号に変換する
		sentence = s.trim();
		sentence = sentence.replaceAll("\n", "%n");
		sentence = sentence.replaceAll(Constant.WAIT_SPACE, "%w");
		sentence = sentence.replaceAll("<", "%lt;");
		sentence = sentence.replaceAll(">", "%gt;");
		sentence = sentence.replaceAll("&", "%amp;");
		sentence = sentence.replaceAll("'", "%dash;");
	}

	public String getPanelSentence() {
		String s = sentence;
		s = s.replaceAll("%n", "\n");
		s = s.replaceAll("%w", Constant.WAIT_SPACE);
		s = s.replaceAll("%lt;", "<");
		s = s.replaceAll("%gt;", ">");
		s = s.replaceAll("%amp;", "&");
		s = s.replaceAll("%dash;", "'");
		return s;
	}

	public String getProblemCreationSentence() {
		String s = sentence;
		s = s.replaceAll("%lt;", "<");
		s = s.replaceAll("%gt;", ">");
		s = s.replaceAll("%amp;", "&");
		s = s.replaceAll("%dash;", "'");
		return s;
	}

	private static final String[] REMOVE = { "!<div>", "<\\/div>", "<object.*?object>" };

	public String getProblemReportSentence() {
		final StringBuilder b = new StringBuilder(sentence);
		for (int i = 0; i < answer.length; ++i) {
			if (answer[0].length() == 0) {
				continue;
			}
			b.append(" ");
			b.append(answer[i]);
		}

		String s = b.toString();
		s = s.replaceAll("%lt;", "<");
		s = s.replaceAll("%gt;", ">");
		s = s.replaceAll("%amp;", "&");
		s = s.replaceAll("%dash;", "'");
		s = s.replaceAll("%w", " ");
		s = s.replaceAll("%n", " ");
		s = s.replaceAll("%c", " ");
		s = s.replaceAll(" +", " ");

		for (int i = 0; i < REMOVE.length; ++i) {
			s = s.replaceAll(REMOVE[i], "");
		}

		s = s.trim();
		return s;
	}

	public String toString() {
		final StringBuffer buffer = new StringBuffer();
		buffer.append(problemId).append(" - ");
		buffer.append(genre).append(" - ");
		buffer.append(type).append(" - ");
		buffer.append(sentence).append(" - ");

		if (answer != null) {
			for (int i = 0; i < answer.length; ++i) {
				buffer.append(answer[i]).append(" - ");
			}
		}
		if (choice != null) {
			for (int i = 0; i < choice.length; ++i) {
				buffer.append(choice[i]).append(" - ");
			}
		}
		return buffer.toString();
	}

	private transient Polygon[] polygons = null;
	private transient Map<String, Boolean> answerCache = new HashMap<String, Boolean>();

	public boolean isCorrect(String answer) {
		if (answerCache.containsKey(answer)) {
			return answerCache.get(answer);
		}

		final boolean result = isCorrectHelper(answer);
		answerCache.put(answer, result);
		return result;
	}

	private boolean isCorrectHelper(String answer) {
		if (answer == null || answer.length() == 0) {
			return false;
		}

		if (type == Constant.TYPE_TATO) {
			// 一問多答
			String selected[] = answer.split(Constant.DELIMITER_GENERAL);
			int numberOfAnswer = 0;
			for (; numberOfAnswer < this.answer.length; ++numberOfAnswer) {
				if (this.answer[numberOfAnswer].length() == 0) {
					break;
				}
			}

			if (selected.length != numberOfAnswer) {
				return false;
			}

			for (int i = 0; i < numberOfAnswer; ++i) {
				boolean contain = false;
				for (int j = 0; j < this.answer.length && !contain; ++j) {
					contain = (selected[i].equals(this.answer[j]));
				}

				if (!contain) {
					return false;
				}
			}

			return true;

		} else if (type == Constant.TYPE_JUNBAN) {
			// 順番当て
			String selected[] = answer.split(Constant.DELIMITER_GENERAL);
			for (int i = 0; i < selected.length; ++i) {
				if (!selected[i].equals(this.answer[i])) {
					return false;
				}
			}

			return true;

		} else if (type == Constant.TYPE_SENMUSUBI) {
			for (int i = 0; i < choice.length; ++i) {
				if (choice[i].length() == 0) {
					break;
				}

				String pair = choice[i] + Constant.DELIMITER_KUMIAWASE_PAIR + this.answer[i];
				if (answer.indexOf(pair) == -1) {
					return false;
				}
			}

			return true;

		} else if (type == Constant.TYPE_SLOT) {
			return this.answer[0].equals(answer);

		} else if (type == Constant.TYPE_CLICK) {
			if (polygons == null) {
				final int numberOfAnswer = getNumberOfAnswer();
				polygons = new Polygon[numberOfAnswer];
				for (int i = 0; i < numberOfAnswer; ++i) {
					polygons[i] = new Polygon(this.answer[i]);
				}
			}

			final Point point = new Point(answer);
			for (Polygon polygon : polygons) {
				if (polygon.contains(point)) {
					return true;
				}
			}

		} else {
			// その他
			for (int i = 0; i < this.answer.length; ++i) {
				if (this.answer[i].length() == 0) {
					continue;
				}
				if (this.answer[i].equals(answer)) {
					return true;
				}
			}
		}

		return false;
	}

	public int getNumberOfAnswer() {
		if (answer == null) {
			return 0;
		}

		for (int i = 0; i < answer.length; ++i) {
			if (answer[i].length() == 0) {
				return i;
			}
		}

		return answer.length;
	}

	public int getNumberOfChoice() {
		if (choice == null) {
			return 0;
		}

		for (int i = 0; i < choice.length; ++i) {
			if (choice[i].length() == 0) {
				return i;
			}
		}

		return choice.length;
	}

	public String getSearchQuery() {
		final StringBuffer builder = new StringBuffer();
		builder.append(sentence).append(' ');

		if (choice != null) {
			for (int i = 0; i < choice.length; ++i) {
				if (choice[i] != null && choice[i].length() != 0) {
					builder.append(choice[i]).append(' ');
				}
			}
		}

		if (answer != null) {
			for (int i = 0; i < answer.length; ++i) {
				if (answer[i] != null && answer[i].length() != 0) {
					builder.append(answer[i]).append(' ');
				}
			}
		}

		return builder.toString();
	}

	public void createRandomizedData(int permutations[][]) {
		if (answer != null) {
			final int[] permutation = permutations[0];
			randomizedAnswer = new String[permutation.length];
			for (int i = 0; i < permutation.length; ++i) {
				randomizedAnswer[permutation[i]] = answer[i];
			}
		}
		if (choice != null) {
			final int[] permutation = permutations[1];
			randomizedChoice = new String[permutation.length];
			for (int i = 0; i < permutation.length; ++i) {
				randomizedChoice[permutation[i]] = choice[i];
			}
		}
	}

	public int getRandomizedAnswerIndex(String answer) {
		for (int i = 0; i < 4; ++i) {
			if (randomizedAnswer[i].equals(answer)) {
				return i;
			}
		}
		return Integer.MAX_VALUE;
	}

	public int getRandomizedChoiceIndex(String choice) {
		for (int i = 0; i < 4; ++i) {
			if (randomizedChoice[i].equals(choice)) {
				return i;
			}
		}
		return Integer.MAX_VALUE;
	}

}
